package cn.ht.jywrwater.module.ht.service.waterleakageanalysis;

import cn.ht.jywrwater.module.ht.dal.dataobject.waterqualityalertcount.WaterQualityAlertCountDO;
import cn.ht.jywrwater.module.ht.dal.dataobject.watersurvey.WaterSurveyDO;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import cn.ht.jywrwater.module.ht.controller.admin.waterleakageanalysis.vo.*;
import cn.ht.jywrwater.module.ht.dal.dataobject.waterleakageanalysis.WaterLeakageAnalysisDO;
import cn.ht.jywrwater.framework.common.pojo.PageResult;

import cn.ht.jywrwater.module.ht.convert.waterleakageanalysis.WaterLeakageAnalysisConvert;
import cn.ht.jywrwater.module.ht.dal.mysql.waterleakageanalysis.WaterLeakageAnalysisMapper;

import static cn.ht.jywrwater.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.ht.jywrwater.module.ht.enums.ErrorCodeConstants.*;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;

/**
 * 漏损分析 Service 实现类
 *
 * @author hzx
 */
@Service
@Validated
public class WaterLeakageAnalysisServiceImpl implements WaterLeakageAnalysisService {

    @Resource
    private WaterLeakageAnalysisMapper waterLeakageAnalysisMapper;

    @Override
    public Long createWaterLeakageAnalysis(WaterLeakageAnalysisCreateReqVO createReqVO) {
        // 插入
        WaterLeakageAnalysisDO waterLeakageAnalysis = WaterLeakageAnalysisConvert.INSTANCE.convert(createReqVO);
        waterLeakageAnalysisMapper.insert(waterLeakageAnalysis);
        // 返回
        return waterLeakageAnalysis.getId();
    }

    @Override
    public void updateWaterLeakageAnalysis(WaterLeakageAnalysisUpdateReqVO updateReqVO) {
        // 校验存在
        validateWaterLeakageAnalysisExists(updateReqVO.getId());
        // 更新
        WaterLeakageAnalysisDO updateObj = WaterLeakageAnalysisConvert.INSTANCE.convert(updateReqVO);
        waterLeakageAnalysisMapper.updateById(updateObj);
    }

    @Override
    public void deleteWaterLeakageAnalysis(Long id) {
        // 校验存在
        validateWaterLeakageAnalysisExists(id);
        // 删除
        waterLeakageAnalysisMapper.deleteById(id);
    }

    private void validateWaterLeakageAnalysisExists(Long id) {
        if (waterLeakageAnalysisMapper.selectById(id) == null) {
            throw exception(WATER_LEAKAGE_ANALYSIS_NOT_EXISTS);
        }
    }

    @Override
    public WaterLeakageAnalysisDO getWaterLeakageAnalysis(Long id) {
        return waterLeakageAnalysisMapper.selectById(id);
    }

    @Override
    public List<WaterLeakageAnalysisDO> getWaterLeakageAnalysisList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return ListUtil.empty();
        }
        return waterLeakageAnalysisMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<WaterLeakageAnalysisDO> getWaterLeakageAnalysisPage(WaterLeakageAnalysisPageReqVO pageReqVO) {
        return waterLeakageAnalysisMapper.selectPage(pageReqVO);
    }

    @Override
    public List<WaterLeakageAnalysisDO> getWaterLeakageAnalysisList(WaterLeakageAnalysisExportReqVO exportReqVO) {
        return waterLeakageAnalysisMapper.selectList(exportReqVO);
    }

    @Override
    public WaterLeakageAnalysisVO getAnalysisList(String region, LocalDate beginDate, LocalDate endDate) {
        WaterLeakageAnalysisVO waterLeakageAnalysisVO = new WaterLeakageAnalysisVO();
        QueryWrapper<WaterLeakageAnalysisDO> queryWrapper = new QueryWrapper<>();
        if (region!=null && !region.equals("")){
            queryWrapper.eq("region", region);
        }
        if (beginDate!=null){
            queryWrapper.ge("data_date", beginDate);
        }
        if (endDate!=null){
            queryWrapper.le("data_date", endDate);
        }

        List<WaterLeakageAnalysisDO> waterLeakageAnalysisDOList = waterLeakageAnalysisMapper.selectList(queryWrapper);

        // 供水总量
        if (waterLeakageAnalysisDOList.size()>0){
            Long provideCounts = waterLeakageAnalysisDOList.stream()
                    .filter(waterLeakageAnalysis -> waterLeakageAnalysis.getType() == 0).map(WaterLeakageAnalysisDO::getWaterCount).reduce(Long::sum).get();
            // 有效供水量
            Long effectiveCounts = waterLeakageAnalysisDOList.stream()
                    .filter(waterLeakageAnalysis -> waterLeakageAnalysis.getType() == 1).map(WaterLeakageAnalysisDO::getWaterCount).reduce(Long::sum).get();

            // 管网漏损量
            Integer leakageCount = provideCounts.intValue() - effectiveCounts.intValue();
            // 管网漏损率
            Double leakageRate = NumberUtil.div(leakageCount.doubleValue()/provideCounts.doubleValue(),100d);

            waterLeakageAnalysisVO.setLeakageCount(leakageCount);
            waterLeakageAnalysisVO.setLeakageRate(leakageRate);

            // 日期的漏算分析

            Map<LocalDate,WaterLeakageData> dateData = MapUtil.newHashMap();
            List<LocalDate> difDateList = waterLeakageAnalysisDOList.stream().map(WaterLeakageAnalysisDO::getDataDate).distinct().collect(Collectors.toList());
            // 所有供水list
            List<WaterLeakageAnalysisDO> waterLeakageAnalysisDateProvideList = waterLeakageAnalysisDOList.stream()
                    .filter(waterLeakageAnalysis -> waterLeakageAnalysis.getType() == 0).collect(Collectors.toList());
            // 有效供水list
            List<WaterLeakageAnalysisDO> waterLeakageAnalysisDateEffectiveList = waterLeakageAnalysisDOList.stream()
                    .filter(waterLeakageAnalysis -> waterLeakageAnalysis.getType() == 1).collect(Collectors.toList());
            for (LocalDate difDate:difDateList){
                Long provideCountDate = waterLeakageAnalysisDateProvideList.stream()
                        .filter(waterLeakageAnalysis -> waterLeakageAnalysis.getDataDate().equals(difDate)).map(WaterLeakageAnalysisDO::getWaterCount).reduce(Long::sum).orElse(0L);
                Long effectiveCountDate = waterLeakageAnalysisDateEffectiveList.stream()
                        .filter(waterLeakageAnalysis -> waterLeakageAnalysis.getDataDate().equals(difDate)).map(WaterLeakageAnalysisDO::getWaterCount).reduce(Long::sum).orElse(0L);
                // 管网漏损量
                Integer leakageCountDate = provideCountDate.intValue() - effectiveCountDate.intValue();
                // 管网漏损率
                Double leakageRateDate = NumberUtil.div(leakageCountDate.doubleValue()/provideCountDate.doubleValue(),100d);
                WaterLeakageData waterLeakageData = new WaterLeakageData();
                waterLeakageData.setLeakageCount(leakageCountDate);
                waterLeakageData.setLeakageRate(leakageRateDate);
                dateData.put(difDate,waterLeakageData);
            }
            waterLeakageAnalysisVO.setDateData(dateData);
        }


        return waterLeakageAnalysisVO;
    }

}
